home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / cw_defroi.pro < prev    next >
Text File  |  1997-07-08  |  12KB  |  317 lines

  1. ; $Id: cw_defroi.pro,v 1.6 1997/01/15 03:11:50 ali Exp $
  2. ;
  3. ; Copyright (c) 1993-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    CW_DEFROI
  8. ;
  9. ; PURPOSE:
  10. ;   Widget to define a region of interest within a widget drawable. 
  11. ; CATEGORY:
  12. ;   Regions of interest, graphics.
  13. ; CALLING SEQUENCE:
  14. ;   Result = CW_DEFROI(draw)
  15. ; INPUTS:
  16. ;   Draw = id of drawable to draw the region.  The drawable should
  17. ;     have both MOTION and BUTTON events enabled.
  18. ; KEYWORD PARAMETERS:
  19. ;   IMAGE_SIZE = the size of the underlying array, expressed
  20. ;       as a two element vector: [columns, rows].  Default =
  21. ;       drawable size / zoom.
  22. ;   OFFSET = offset of lower left corner of image within the
  23. ;       drawable.  Default = [0,0].
  24. ;   ORDER = if set, return inverted subscripts, as if the array
  25. ;       were output from top to bottom.
  26. ;   RESTORE = Set to restore the drawable to its previous appearance
  27. ;       on exit.  Otherwise, the regions remain on the drawable.
  28. ;   ZOOM = if the image array was expanded (via REBIN for example)
  29. ;       specify this two element vector containing the expansion
  30. ;       factor in X and Y.  Default = [1,1].  Must be integer.
  31. ; OUTPUTS:
  32. ;      Result = subscripts of points within the region[s] defined.
  33. ;       If no region was defined, a scalar -1 is returned.
  34. ; COMMON BLOCKS:
  35. ;       None.
  36. ; SIDE EFFECTS:
  37. ;       The regions are drawn within the drawable.  Set the RESTORE
  38. ;       keyword to undo the damage.  
  39. ; RESTRICTIONS:
  40. ;   This is a MODAL widget.  No other widget applications will be
  41. ;   responsive while this widget is in use.
  42. ;
  43. ; PROCEDURE:
  44. ;   Complicated.
  45. ; EXAMPLE:
  46. ;   To obtain the average of the counts of a region within a drawable:
  47. ;   Assume A = the array of interest, n columns, m rows, and that
  48. ;   it is displayed in drawable D, at offset X=20, Y=100, and zoomed
  49. ;   with a factor of 2:
  50. ;       TV, REBIN(A, M*2, N*2), 20, 100     ;Display the image
  51. ;       q = CW_DEFROI(D, ZOOM=[2,2], OFFSET=[20,100], IMAGE_SIZE=[m,n])
  52. ;       if q(0) ne -1 then print,'Average = ', total(a(q))/n_elements(q)
  53. ;       
  54. ; MODIFICATION HISTORY:
  55. ;   DMS, RSI, December, 1993.  Written.
  56. ;-
  57.  
  58. pro CW_DEFROI_nmode, s, new
  59. ; Set new mode... Save old roi by concatenating it with s.subs.
  60. n = s.npts
  61. if (s.mode ne 1) and (n le 2) then n = 0  ;must have 3 pnts for polygon
  62. WIDGET_CONTROL, s.mode_w, SET_VALUE=0       ;Revert to add mode
  63. s.amode = 0
  64.  
  65. if n ge 1 then begin       ;Old region to save?
  66.     if s.mode eq 1 then begin   ;Points?
  67.         WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY  ;Get old ROI
  68.         xy = xy[0,0:n-1] + s.image_size[0] * xy[1,0:n-1] ;points to subs
  69.         xy = REFORM(xy, n_elements(xy), /OVERWRITE) ;Make linear
  70.     endif else begin
  71.         CW_DEFROI_DRAW, s, -1, /FILL
  72.         WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY  ;Get old ROI
  73.         xy = polyfillv(xy[0,0:n-1],xy[1,0:n-1],s.image_size[0], s.image_size[1])
  74.     ENDELSE
  75.     WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY      ;Prev roi pnts
  76.         ;Concatenate s and xy
  77.     if n_elements(t) le 0 then WIDGET_CONTROL, s.subs, SET_UVALUE=xy, /NO_COPY $
  78.     else WIDGET_CONTROL, s.subs, SET_UVALUE=[t,xy], /NO_COPY
  79.     endif               ;Old region to save
  80.  
  81. s.mode = new
  82. s.npts = 0
  83. end
  84.  
  85. PRO CW_DEFROI_DRAW, s, i, FILL = fill
  86. ; Draw the outline (or polygon if FILL is set) 
  87. ; of the region or the ith segment if i < 0.
  88. ; Use the XOR drawing mode.
  89.  
  90. n = s.npts
  91. if n lt 1 then return
  92.    
  93. WSET, s.win   
  94. DEVICE, SET_GRAPHICS=6          ;Xor drawing mode   
  95. col = 1
  96. while col lt !d.table_size do col = col + col
  97. WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY  ;Get ROI
  98.   xsave = !x.s & ysave = !y.s       ;Set scaling to pixel coords
  99.   p = float([!d.x_size, !d.y_size])
  100.   f = s.offset / p
  101.   q = s.zoom / p
  102.   !x.s = [f[0], q[0]]
  103.   !y.s = [f[1], q[1]]
  104.  
  105. if s.mode eq 1 then BEGIN       ;Point mode?
  106.     if i lt 0 then begin
  107.         i = 0 & i1 = n-1
  108.     ENDIF else i1 = i
  109.     for j = i, i1 do $
  110.         polyfill, xy[0,j] + [0, .9, .9, 0], xy[1,j] + [0,0,.9,.9], COLOR=col
  111. ENDIF ELSE BEGIN            ;Polygon/circle/rect
  112.     if n ge 2 then begin
  113.         if i lt 0 then plots, COLOR=col, xy[*, 0:n-1]+.5 $ ;All of it?
  114.         else plots, COLOR=col, xy[*, i:i+1]+.5  ;One segment
  115.         IF KEYWORD_SET(FILL) then POLYFILL, xy[*,0:n-1], COLOR=col
  116.     ENDIF
  117. ENDELSE
  118.  
  119. !x.s = xsave & !y.s = ysave
  120. WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY  ;Set ROI   
  121. DEVICE, SET_GRAPHICS=3          ;Copy mode   
  122. end   
  123.    
  124.    
  125. PRO CW_DEFROI_event, ev, s
  126. ; This routine is only called from the CW_DEFROI event loop.
  127. ; ev = event structure, s = state structure.
  128.  
  129.  
  130. s.button = s.button or ev.press xor ev.release  ;New button state   
  131. n = s.npts
  132. x = (ev.x - s.offset[0]) / s.zoom[0]    ;Pixel coordinates
  133. y = (ev.y - s.offset[1]) / s.zoom[1]   
  134.  
  135. if s.order then y0 = s.image_size[1]-y-1 else y0 = y
  136. WIDGET_CONTROL, s.pos_w, $
  137.     SET_VALUE=string(x, y0, format='("Position: ",i,", ",i)')
  138.  
  139. if (x lt 0) or (y lt 0) or $            ;Within region?
  140.     (x ge s.image_size[0]) or (y ge s.image_size[1]) then return
  141. if ev.press ne 0 then s.drag = [x,y]    ;Start of drag operation
  142.  
  143.  
  144. if (s.mode eq 2) or (s.mode eq 3) then begin ;Rect or square?
  145.     if s.button ne 0 then begin          ;Drag
  146.         if n gt 0 then CW_DEFROI_draw, s, -1      ;Remove old
  147.         t = s.drag
  148.         if s.mode eq 2 then begin   ;Rectangle
  149.             n = 5
  150.             xy = [[t], [x, t[1]], [x, y], [t[0], y], [t]]
  151.         endif else begin        ;Circle
  152.             n = 30              ;# of points
  153.             a = findgen(n+1) * (2 * !pi/(n-1))
  154.             r = sqrt((float(x)-t[0])^2 + (float(y) - t[1])^2)
  155.             xy = transpose([[t[0] + r * cos(a)], [t[1] + r * sin(a)]])
  156.         endelse
  157.     WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY   ;Restore UVALUE
  158.     s.npts = n
  159.     CW_DEFROI_draw, s, -1
  160.     ENDIF                       ;DRAG
  161.     return
  162. ENDIF                           ;Rect or square
  163.  
  164.  
  165. if s.button eq 0 then return        ;Must be point or polygon...
  166. tmode = s.amode                     ;Default mode
  167. if s.button eq 4 then tmode = 1     ;Rt button to remove
  168.  
  169. if tmode then begin            ;Remove prev point?
  170.     if (ev.press ne 0) and (n gt 0) then begin
  171.         CW_DEFROI_DRAW, s, -1   ;Erase old region
  172.         WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY ;Get ROI array
  173.         d = float(x-xy[0,0:n-1])^2 + float(y-xy[1,0:n-1])^2  ;Dist
  174.         t = min(d, ipnt)        ;Closest...
  175.         if ipnt ne (n-1) then xy[0,ipnt] = xy[*,ipnt+1:*]  ;Collapse
  176.         s.npts = n-1
  177.         WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY  ;Save ROI array
  178.         if n gt 1 then CW_DEFROI_DRAW, s, -1   ;Draw new region
  179.         endif   
  180.     return
  181.     endif               ;Remove mode....   
  182.            
  183. ; Here we add a point
  184. WIDGET_CONTROL, s.xy_pnts, GET_UVALUE=xy, /NO_COPY  ;Get ROI array
  185.  
  186. ; Add a point
  187. if n_elements(xy) le 1 then xy = intarr(2,100)   
  188.         ; Remove duplicates...   
  189. if n gt 0 then if x eq xy[0,n-1] and y eq xy[1,n-1] then goto, done0
  190. if s.mode eq 1 then for i=0, n-1 do $       ;Point mode?
  191.     IF x eq xy[0,i] and y eq xy[1,i] then goto, done0    ;No duplicates
  192.  
  193. if (n+1) ge n_elements(xy)/2 then xy = [[xy], [intarr(2,n)]]  ;Extend array?
  194.  
  195. xy[0,n] = x     ;New point
  196. xy[1,n] = y
  197. n = n + 1
  198. s.npts = n
  199. WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY   ;Restore UVALUE
  200.  
  201. if s.mode eq 0 then begin           ;Polygon?
  202.     if n ge 2 then CW_DEFROI_draw, s, n-2           ;Draw the new segment
  203. endif else begin                    ;Point
  204.     CW_DEFROI_draw, s, n-1         ;Draw new point
  205. endelse
  206. return
  207.    
  208. done0: WIDGET_CONTROL, s.xy_pnts, SET_UVALUE=xy, /NO_COPY   
  209. end   
  210.    
  211.  
  212.  
  213.  
  214. function CW_DEFROI, draw, ZOOM = zoom, IMAGE_SIZE = image_size, $   
  215.     OFFSET = offset, RESTORE = restore, ORDER = order
  216.  
  217. base = widget_base(title='Region of Interest', /COLUMN)   
  218. xy_pnts = WIDGET_TEXT(base, YSIZE=2, /FRAME, UVALUE=0, $
  219.     value=['Add with left button: drag or click', $   
  220.         'Remove with right button'])   
  221. Options = CW_BGROUP(base, /ROW, /NO_RELEASE, /RETURN_NAME,  $
  222.     ['Clear', 'Clear All', 'New', 'Cancel'])   
  223. junk = CW_BGROUP(base, /ROW, /EXCLUSIVE, /NO_REL, /RETURN_NAME, $
  224.     ['Polygon', 'Point', 'Rectangle', 'Circle'], SET_VALUE=0)
  225. mode_w = CW_BGROUP(base, /ROW, LABEL_LEFT = 'Mode:', /EXCLUSIVE, /NO_REL, $   
  226.     /RETURN_NAME, ['Add', 'Remove'], SET_VALUE=0)
  227. junk = CW_BGROUP(base, /ROW, /NO_REL, /RETURN_NAME, ['Done'])
  228. pos_w = WIDGET_TEXT(base, YSIZE=1, XSIZE=18, /FRAME, $
  229.     VALUE='Position:    0,    0')
  230.  
  231. WIDGET_CONTROL, draw, GET_VALUE=win
  232. WSET, win   
  233.    
  234. if n_elements(zoom) le 0 then zoom = [1,1]
  235. if n_elements(image_size) le 0 then image_size = [!d.x_size, !d.y_size] / zoom
  236. if n_elements(offset) le 0 then offset = [0,0]   
  237. p  = offset + image_size /2   
  238. if (!version.os NE 'MacOS') THEN TVCRS, p[0], p[1], /DEVICE ELSE TVCRS, 1
  239.    
  240. WINDOW, /PIXMAP, /FREE, xs = !d.x_size, ys=!d.y_size  ;Save window
  241. backing = !d.window
  242. DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, win]  ;Save it
  243.  
  244. s = { CW_DEFROI_STRUCT, $       ;Structure containing state
  245.     base: base, $       ;Main base widget
  246.     xy_pnts: xy_pnts, $ ;Current roi vertex list
  247.     npts : 0L, $        ;# of points in current roi
  248.     subs : pos_w, $     ;Widget holding prev subscripts
  249.     pos_w : pos_w, $    ;Position text widget
  250.     mode: 0, $          ;major mode
  251.     amode: 0, $         ;0 for add, 1 for remove
  252.     draw: draw, $       ;draw widget id
  253.     win:  win, $        ;draw widget window #
  254.     button: 0, $        ;button state
  255.     image_size : long(image_size), $   ;Image array size
  256.     mode_w: mode_w, $   ;Add/remove button widget
  257.     backing: backing, $ ;Pixmap for backing store
  258.     offset: fix(offset), $   ;offset of array within window
  259.     zoom : fix(zoom), $ ;zoom factor
  260.     order : KEYWORD_SET(order), $  ;Image order
  261.     drag: [0,0]}        ;Beginning of drag motion
  262.    
  263. WIDGET_CONTROL, base, /REALIZE
  264. WSHOW, win
  265.    
  266. WHILE 1 DO BEGIN                ;Internal event loop   
  267.     ev = WIDGET_EVENT([base, draw])
  268.     n = s.npts
  269.     if ev.id eq draw then CW_DEFROI_EVENT, ev, s $
  270.     else case ev.value of   
  271. 'Clear All':  BEGIN
  272.     WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY  ;Clr list of subscripts
  273.     t = 0
  274.     WSET, win
  275.     DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, backing]  ;Restore it
  276.     s.npts = 0
  277.     ENDCASE
  278. 'Clear':  BEGIN   
  279.     if (n ge 2) or (s.mode eq 1 and n ge 1) then $
  280.         CW_DEFROI_draw, s, -1        ;Erase roi   
  281.     s.npts = 0   
  282.     CW_DEFROI_NMODE, s, s.mode
  283.     ENDCASE
  284. 'New' : CW_DEFROI_nmode, s, s.mode      ;Make a new region...
  285. 'Cancel':  BEGIN   
  286.     xy = -1
  287.     goto, all_done
  288.     ENDCASE    
  289.  
  290. ;    ['Polygon', 'Point', 'Rectangle', 'Circle'], SET_VALUE=0)
  291. 'Polygon': CW_DEFROI_nmode, s, 0
  292. 'Point' :  CW_DEFROI_nmode, s, 1
  293. 'Rectangle' :  CW_DEFROI_nmode, s, 2
  294. 'Circle' :  CW_DEFROI_nmode, s, 3
  295.  
  296. 'Add':  s.amode = 0
  297. 'Remove': s.amode = 1
  298. 'Done': BEGIN   
  299.     cw_defroi_nmode, s, 0       ;Save old region
  300.     WIDGET_CONTROL, s.subs, GET_UVALUE=t, /NO_COPY  ;List of subscripts
  301.     xy = BYTARR(s.image_size[0], s.image_size[1])  ;Return only unique
  302.     if n_elements(t) gt 0 then xy[t] = 1
  303.     if s.order then xy = reverse(xy,2)  ;Flip it?
  304.     xy = where(temporary(xy))
  305. all_done:
  306.     IF KEYWORD_SET(restore) then begin      ;Undo damage?
  307.         WSET, win
  308.         DEVICE, copy = [0,0, !d.x_size, !d.y_size, 0, 0, backing]  ;Restore it
  309.         ENDIF
  310.     WDELETE, backing
  311.     WIDGET_CONTROL, base, /DESTROY   
  312.     return, xy
  313.     ENDCASE    
  314. ENDCASE   
  315. ENDWHILE            ;Event loop
  316. END   
  317.